package com.sky.aop;

import com.sky.annotation.AutoFill;
import com.sky.annotation.AutoInsertFill;
import com.sky.annotation.AutoUpdateFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * AutoFillAspect
 *
 * @author liliudong
 * @version 1.0
 * @description 字段自动注入AOP
 * @date 2023/7/28 9:23
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    @Pointcut("@annotation(com.sky.annotation.AutoFill) " +
            "|| @annotation(com.sky.annotation.AutoInsertFill) " +
            "|| @annotation(com.sky.annotation.AutoUpdateFill)")
    public void pt() {
    }

    /**
     * 自动填充
     * 目标：拦截到方法之后，根据新增、更新进行属性的动态注入
     * 使用规范：
     * 1.切点注解必须在Mapper的方法上
     * 2.这个方法的第一个参数必须是实体
     * 3.这个实体里面一定得有createTime等四个属性 set方法
     *
     * @param joinPoint 连接点
     */
    @Before("pt()")
    public void autoFill(JoinPoint joinPoint) {
        // 拦截到有注解的方法

        // 取方法上面的注解，然后取这个注解的Value值
        // 1. 怎么拿到这个注解呢？
        MethodSignature sign = (MethodSignature) joinPoint.getSignature();
        Method method = sign.getMethod();
        // 获取方法上的注解
        AutoFill autoFill = method.getAnnotation(AutoFill.class);
        AutoInsertFill autoInsertFill = method.getAnnotation(AutoInsertFill.class);
        AutoUpdateFill autoUpdateFill = method.getAnnotation(AutoUpdateFill.class);

        OperationType operationType = null;
        if (autoFill != null) {
            operationType = autoFill.value();
        }
        if (autoInsertFill != null) {
            operationType = OperationType.INSERT;
        }
        if (autoUpdateFill != null) {
            operationType = OperationType.UPDATE;
        }

        // 2. 应该要获取到 category这个对象
        Object[] args = joinPoint.getArgs();
        Object object = args[0];
        try {
            // 3. 是新增、四个属性，是更新，两个属性
            Class<?> clazz = object.getClass();
            if (Objects.equals(OperationType.INSERT, operationType)) {
                // 通过反射赋值
                Method setCreateTime = clazz.getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setUpdateTime = clazz.getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setCreateUser = clazz.getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateUser = clazz.getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                setCreateTime.invoke(object, LocalDateTime.now());
                setUpdateTime.invoke(object, LocalDateTime.now());
                setCreateUser.invoke(object, BaseContext.getCurrentId());
                setUpdateUser.invoke(object, BaseContext.getCurrentId());

            }

            if (Objects.equals(OperationType.UPDATE, operationType)) {
                // 更新
                Method setUpdateTime = clazz.getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = clazz.getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                setUpdateTime.invoke(object, LocalDateTime.now());
                setUpdateUser.invoke(object, BaseContext.getCurrentId());
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

    }

}
